/**
	Pulsar engine. Core.
	Standard events

	Copyright (C) 2013-2014 Dmitry Dolgov

	This program is free software; you can redistribute it and/or modify it under the terms of the
	GNU General Public License as published by the Free Software Foundation; either version 2 of
	the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
	without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
	See the GNU General Public License for more details.
*/

#include <pulsar/pulsar.h>

namespace pl
{

/// INewFrame subscribers
List<INewFrame> INewFrame::_newFrameGroup;
pl_uint32 INewFrame::frameCounter = 0;
/// IAppEvents subscribers
List<IAppEvents> IAppEvents::_appEventsGroup;
/// IAppDebug subscribers
List<IAppDebug> IAppDebug::_appDebugGroup;

} // namespace pl

/**
	INewFrame subscriber ctor
*/
pl::INewFrame::INewFrame() :
ListNode<INewFrame>(_newFrameGroup)
{
	return;
}

/**
	Notify INewFrame subscribers about new frame
*/
bool pl::INewFrame::callOnNewFrame()
{
	pl::ListEnumerator<INewFrame> enumForw(_newFrameGroup);

	frameCounter++;
	while (!enumForw.isFinished())
	{
		enumForw->onNewFrame(frameCounter);
	}
	return false;
}

/**
	IAppEvents subscriber ctor
*/
pl::IAppEvents::IAppEvents() :
ListNode<IAppEvents>(_appEventsGroup)
{
	return;
}

/**
	Notify IAppEvents subscribers about fatal error
*/
void pl::IAppEvents::callOnFatal(int exitCode, const pl_char* diags)
{
	pl::ListEnumerator<IAppEvents> enumForw(_appEventsGroup);
	while (!enumForw.isFinished())
	{
		enumForw->onFatal(exitCode, diags);
	}
	pl::AppBase::appBase->terminateProcess(exitCode);
	return;
}

/**
	Notify IAppEvents subscribers about exception
*/
void pl::IAppEvents::callOnException(const pl::ExceptionInfo& info)
{
	pl::ListEnumerator<IAppEvents> enumForw(_appEventsGroup);
	while (!enumForw.isFinished())
	{
		enumForw->onException(info);
	}
	return;
}

/**
	Notify IAppEvents subscribers about signal
*/
pl::HandleResult pl::IAppEvents::callOnSignal(SignalInfo code)
{
	pl::ListEnumerator<IAppEvents> enumForw(_appEventsGroup);
	while (!enumForw.isFinished())
	{
		HandleResult rc = enumForw->onSignal(code);
		if (rc == HANDLE_RESULT_IGNORE || rc == HANDLE_RESULT_DEBUG)
		{
			return rc;
		}
	}
	return HANDLE_RESULT_NEXT;
}

/**
	IAppDebug subscriber ctor
*/
pl::IAppDebug::IAppDebug() :
ListNode<IAppDebug>(_appDebugGroup)
{
	return;
}

/**
	Notify IAppDebug subscribers about assert
*/
pl::HandleResult pl::IAppDebug::callOnAssert(const pl_char* file, pl_uint32 line, const pl_char* func, const pl_char* cond, const pl_char* msg, pl::AssertType type)
{
	pl::ListEnumerator<IAppDebug> enumForw(_appDebugGroup);

	while (!enumForw.isFinished())
	{
		HandleResult rc = enumForw->onAssert(file, line, func, cond, msg, type);
		if (rc == HANDLE_RESULT_IGNORE || rc == HANDLE_RESULT_DEBUG)
		{
			return rc;
		}
	}
	return HANDLE_RESULT_NEXT;
}

/**
	Notify IAppDebug subscribers about thread events
*/
void pl::IAppDebug::callOnThread(pl::ThreadEvent evt, const pl_char* threadName)
{
	pl::ListEnumerator<IAppDebug> enumForw(_appDebugGroup);
	while (!enumForw.isFinished())
	{
		enumForw->onThread(evt, threadName);
	}

	switch (evt)
	{
		case THREAD_EVENT_START:
			plLogDebug(PL_LOG_NAME, PL_T("New thread started: ") << threadName);
			break;
		case THREAD_EVENT_END:
			plLogDebug(PL_LOG_NAME, PL_T("Thread finished: ") << threadName);
			break;
		case THREAD_EVENT_START_JOB:
			plLogDebug(PL_LOG_NAME, PL_T("Thread starts job: ") << threadName);
			break;
		case THREAD_EVENT_END_JOB:
			plLogDebug(PL_LOG_NAME, PL_T("Thread ends job: ") << threadName);
			break;
		case THREAD_EVENT_CANT_DTOR:
			plLogDebug(PL_LOG_NAME, PL_T("Thread can't dtor due to job execution: ") << threadName);
			break;
		default:
			plLogWarn(PL_LOG_NAME, PL_T("Undefined thread event: ") << threadName << PL_T(". Event code: ") << evt);
			break;
	}	
	return;

	return;
}

/**
	Notify IAppDebug subscribers about memory error events
*/
pl::HandleResult pl::IAppDebug::callOnMemErr(const pl_char* file, pl_uint32 line, const pl_char* func, void* p, pl_int64 size, pl::MemoryError idEvent)
{
	pl::ListEnumerator<IAppDebug> enumForw(_appDebugGroup);

	while (!enumForw.isFinished())
	{
		HandleResult rc = enumForw->onMemErr(file, line, func, p, size, idEvent);
		if (rc == HANDLE_RESULT_IGNORE || rc == HANDLE_RESULT_DEBUG)
		{
			return rc;
		}
	}
	return HANDLE_RESULT_NEXT;
}

//
// End of file 'pulsar_events.cpp'
//
